<?php

namespace App\Admin\Form;

use App\Admin\Admin;
use App\Admin\Form;
use App\Admin\Form\Field\Hidden;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class Builder
{
    /**
     * 指定表单中用来指定提交后要返回的地址的字段名
     */
    const PREVIOUS_URL_KEY = '_previous_';

    /**
     * 要构建的表单
     *
     * @var Form
     */
    protected $form;

    /**
     * 表单中各组件
     *
     * @var Collection
     */
    protected $fields;

    /**
     * 编辑和查看时的模型记录id
     *
     * @var mixed
     */
    protected $id;

    /**
     * 当前表单的模式
     *
     * @var string
     */
    protected $mode = 'create';

    /**
     * 此表单的action属性
     *
     * @var string
     */
    protected $action = '';

    /**
     * 表单的查看模式
     */
    const MODE_VIEW = 'view';

    /**
     * 表单的添加模式
     */
    const MODE_CREATE = 'create';

    /**
     * 表单的编辑模式
     */
    const MODE_EDIT = 'edit';

    /**
     * 隐藏显示的字段
     *
     * @var array
     */
    protected $hiddenFields = [];

    /**
     * 表单头部的操作按钮
     *
     * @var Tools
     */
    protected $tools;

    /**
     * 表单底部按钮设置
     *
     * @var array
     */
    protected $options = [
        'enableSubmit' => true,
        'enableReset'  => true,
    ];

    /**
     * 表单每个组件前面的文字和组件各自占用的宽度
     *
     * @var array
     */
    protected $width = [
        'label' => 150,
        'field' => 380,
    ];

    /**
     * 此表单所用的blade
     *
     * @var string
     */
    protected $view = 'admin.form';

    /**
     * Builder constructor.
     * @param Form $form
     */
    public function __construct(Form $form)
    {
        $this->form = $form;
        $this->fields = new Collection();

        $this->setupTools();
    }

    /**
     * 初始化表单头部工具按钮
     */
    protected function setupTools()
    {
        $this->tools = new Tools($this);
    }

    /**
     * 返回此表单的头部工具按钮
     *
     * @return Tools
     */
    public function getTools()
    {
        return $this->tools;
    }

    /**
     * 生成此表单的html字符串
     *
     * @return string
     * @throws \Throwable
     */
    public function render()
    {
        $this->removeDisplayFields();

        $tabObj = $this->form->getTab();

        if (!$tabObj->isEmpty()) {
            $script = <<<SCRIPT
            
var layid = location.hash.replace(/^#/, '');
element.tabChange('tab-form', layid);

SCRIPT;

            Admin::script($script);
        }

        $data = [
            'form'   => $this,
            'tabObj' => $tabObj,
            'width'  => $this->width,
        ];

        return view($this->view, $data)->render();
    }

    /**
     * 【添加】表单中,display组件不用显示
     */
    protected function removeDisplayFields()
    {
        if (!$this->isMode(static::MODE_CREATE)) {
            return;
        }

        $this->fields = $this->fields()->reject(function (Field $field) {
            return $field instanceof Form\Field\Display;
        });
    }

    /**
     * 判断当前表单是不是给定的模式
     *
     * @param $mode
     * @return bool
     */
    public function isMode($mode)
    {
        return $this->mode == $mode;
    }

    /**
     * 返回此表单的所有组件
     *
     * @return Collection
     */
    public function fields()
    {
        return $this->fields;
    }

    /**
     * 获取指定名称的组件
     *
     * @param string $name
     * @return mixed
     */
    public function field($name)
    {
        return $this->fields()->first(function (Field $field) use ($name) {
            return $field->column() == $name;
        });
    }

    /**
     * 获取所有隐藏字段
     *
     * @return array
     */
    public function getHiddenFields()
    {
        return $this->hiddenFields;
    }

    /**
     * 添加隐藏字段
     *
     * @param Field $field
     */
    public function addHiddenField(Field $field)
    {
        $this->hiddenFields[] = $field;
    }

    /**
     * 设置表单的模式,可以为:添加|显示|编辑
     *
     * @param string $mode
     */
    public function setMode($mode = 'create')
    {
        $this->mode = $mode;
    }

    /**
     * 设置该表单的数据的id
     *
     * @param $id
     */
    public function setResourceId($id)
    {
        $this->id = $id;
    }

    /**
     * 获取当前表单的数据的id
     *
     * @return mixed
     */
    public function getResourceId()
    {
        return $this->id;
    }

    /**
     * 返回表单的资源url路径
     *
     * @param int|null $slice 当前路由往前几步的路由地址,按"/"区分步骤
     * @return string
     */
    public function getResource($slice = null)
    {
        if ($this->mode == self::MODE_CREATE) {
            return $this->form->resource(-1);
        }

        if (!is_null($slice)) {
            return $this->form->resource($slice);
        }

        return $this->form->resource();
    }

    /**
     * 设置表单里元素宽度
     *
     * @param int $field
     * @param int $label
     * @return $this
     */
    public function setWidth($field = 380, $label = 150)
    {
        $this->width = compact('field', 'label');

        return $this;
    }

    /**
     * 设置表单的action属性
     *
     * @param $action
     */
    public function setAction($action)
    {
        $this->action = $action;
    }

    /**
     * 获取表单的action属性
     *
     * @return string
     */
    public function getAction()
    {
        if ($this->action) {
            return $this->action;
        }

        if ($this->isMode(static::MODE_EDIT)) {
            return $this->form->resource() . '/' . $this->id;
        }

        if ($this->isMode(static::MODE_CREATE)) {
            return $this->form->resource(-1);
        }

        return '';
    }

    /**
     * 设置表单所用的blade
     *
     * @param $view
     * @return $this
     */
    public function setView($view)
    {
        $this->view = $view;

        return $this;
    }

    /**
     * 获取所有底部按钮的设置或者设置添加设置
     *
     * @param array $options
     * @return array
     */
    public function options($options = [])
    {
        if (empty($options)) {
            return $this->options;
        }

        $this->options = array_merge($this->options, $options);
    }

    /**
     * 按名称获取或者设置一个底部按钮设置项的值
     *
     * @param $option
     * @param null $value
     * @return $this|mixed
     */
    public function option($option, $value = null)
    {
        if (func_num_args() == 1) {
            return array_get($this->options, $option);
        }

        $this->options[$option] = $value;

        return $this;
    }

    /**
     * 获取表单标题
     *
     * @return string
     */
    public function title()
    {
        switch ($this->mode) {
            case static::MODE_CREATE:
                return '添加';
                break;
            case static::MODE_EDIT:
                return '编辑';
                break;
            case static::MODE_VIEW:
                return '详情';
                break;
            default:
                return '';
        }
    }

    /**
     * 判断该表单中是否有文件组件
     *
     * @return bool
     */
    // public function hasFile()
    // {
    //     foreach ($this->fields() as $field) {
    //         if ($field instanceof Field\File) {
    //             return true;
    //         }
    //     }
    //
    //     return false;
    // }

    /**
     * 添加一个隐藏字段,用来在更新和添加后,需要返回的网址
     */
    protected function addRedirectUrlField()
    {
        $previous = \URL::previous();

        if (!$previous || $previous == \URL::current()) {
            return;
        }

        if (Str::contains($previous, url($this->getResource()))) {
            $this->addHiddenField((new Hidden(static::PREVIOUS_URL_KEY))->value($previous));
        }
    }

    /**
     * 返回html表单结构<form>部分
     *
     * @param array $options
     * @return string
     */
    public function open($options = [])
    {
        if ($this->mode == self::MODE_EDIT && $this->option('enableSubmit')) {
            $this->addHiddenField((new Hidden('_method'))->value('PUT'));
        }

        $this->addRedirectUrlField();

        $attributes['action'] = $this->getAction();
        $attributes['method'] = array_get($options, 'method', 'post');
        $attributes['accept-charset'] = 'UTF-8';

        $attributes['class'] = array_get($options, 'class', 'layui-form');

        // if ($this->hasFile()) {
        //     $attributes['enctype'] = 'multipart/form-data';
        // }

        $html = [];
        foreach ($attributes as $name => $value) {
            $html[] = "{$name}='{$value}'";
        }

        return '<form ' . implode(' ', $html) . '>';
    }

    /**
     * 返回html表单结构</form>部分,并做一些清理
     *
     * @return string
     */
    public function close()
    {
        $this->form = null;
        $this->fields = null;

        return '</form>';
    }

    /**
     * 返回表单中提交按钮的html字符串
     *
     * @return string
     */
    public function submitButton()
    {
        if ($this->mode == self::MODE_VIEW) {
            return '';
        }

        if (!$this->options['enableSubmit']) {
            return '';
        }

        return '<button type="submit" class="layui-btn layui-btn-sm" disabled>提交</button>';
    }

    /**
     * 返回表单实例
     *
     * @return Form
     */
    public function form()
    {
        return $this->form;
    }

    /**
     * 返回表单中重置按钮的html字符串
     *
     * @return string
     */
    public function resetButton()
    {
        if (!$this->options['enableReset']) {
            return '';
        }

        return '<input type="reset" class="layui-btn layui-btn-primary layui-btn-sm" value="重置">';
    }

    /**
     * 返回表单顶部的工具按钮的html
     *
     * @return string
     */
    public function renderHeaderTools()
    {
        return $this->tools->render();
    }

    /**
     * 返回表单底部按钮的html
     *
     * @return string
     */
    public function renderFooterButtons()
    {
        return $this->submitButton() . $this->resetButton();
    }

    /**
     * @return string
     * @throws \Throwable
     */
    public function __toString()
    {
        return $this->render();
    }
}